package com.dxy.lc.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dxy.lc.base.AppConstant;
import com.dxy.lc.enums.ReadStatus;
import com.dxy.lc.model.bean.ChatHistoryQo;
import com.dxy.lc.model.bean.MsgPayload;
import com.dxy.lc.model.bean.SetReadDto;
import com.dxy.lc.model.entity.Message;
import com.dxy.lc.mapper.MessageMapper;
import com.dxy.lc.model.entity.MsgStatus;
import com.dxy.lc.model.entity.Room;
import com.dxy.lc.model.entity.RoomUser;
import com.dxy.lc.service.MessageService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dxy.lc.service.MsgStatusService;
import com.dxy.lc.service.RoomService;
import com.dxy.lc.service.RoomUserService;
import com.dxy.lc.socketio.ISessionService;
import com.dxy.lc.utils.LoginUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author dxy
 * @since 2024-11-07
 */
@Slf4j
@Service
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements MessageService {

    @Autowired
    private MsgStatusService msgStatusService;
    @Autowired
    private RoomService roomService;
    @Autowired
    private RoomUserService roomUserService;
    @Autowired
    private ISessionService sessionService;


    @Override
    public void setReadById(SetReadDto param) {
        Assert.notNull(param.getMsgId());
        String loginUserId = LoginUtil.getLoginUserIdOrException();
        Wrapper<MsgStatus> w = new LambdaUpdateWrapper<MsgStatus>()
                .set(MsgStatus::getStatus, Integer.parseInt(ReadStatus.READ.toCode()))
                .set(MsgStatus::getReadAt, LocalDateTimeUtil.parse(param.getReadAt()))
                .eq(MsgStatus::getStatus, Integer.parseInt(ReadStatus.UN_READ.toCode()))
                .eq(MsgStatus::getMsgId, param.getMsgId())
                .eq(MsgStatus::getUserId, Integer.parseInt(loginUserId));
        msgStatusService.update(null, w);
        sendUnreadCount(loginUserId);
    }

    @Override
    public void setReadByRoomId(SetReadDto param) {
        Assert.notNull(param.getRoomId());
        String loginUserId = LoginUtil.getLoginUserIdOrException();
        Wrapper<MsgStatus> w = new LambdaUpdateWrapper<MsgStatus>()
                .set(MsgStatus::getStatus, Integer.parseInt(ReadStatus.READ.toCode()))
                .set(MsgStatus::getReadAt, LocalDateTimeUtil.parse(param.getReadAt()))
                .eq(MsgStatus::getStatus, Integer.parseInt(ReadStatus.UN_READ.toCode()))
                .eq(MsgStatus::getRoomId, param.getRoomId())
                .eq(MsgStatus::getUserId, Integer.parseInt(loginUserId));
        msgStatusService.update(null, w);
        sendUnreadCount(loginUserId);
    }

    @Override
    public long countUnreadMsg(Integer roomId) {
        String loginUserId = LoginUtil.getLoginUserIdOrException();
        // Wrapper<MsgStatus> w = new LambdaQueryWrapper<MsgStatus>()
        //         .eq(roomId != null, MsgStatus::getRoomId, roomId)
        //         .eq(MsgStatus::getStatus, Integer.parseInt(ReadStatus.UN_READ.toCode()))
        //         .eq(MsgStatus::getUserId, Integer.parseInt(loginUserId));
        // return msgStatusMapper.selectCount(w);
        return msgStatusService.countUnreadMsg(roomId, Integer.parseInt(loginUserId));
    }

    @Override
    public List<Message> getChatHistory(ChatHistoryQo param) {
        String loginUserId = LoginUtil.getLoginUserIdOrException();
        param.setUserId(Integer.parseInt(loginUserId));
        return baseMapper.getList(param);
    }

    @Override
    @Transactional
    public void saveAndSendMsg(MsgPayload data) {
        // 保存消息
        Message m = new Message()
                .setRoomId(data.getRoomId())
                .setMsgType(data.getMsgType())
                .setContent(data.getContent())
                .setSentAt(LocalDateTimeUtil.parse(data.getSentAt())) // yyyy-MM-ddTHH:mm:ss
                .setSentBy(data.getSentBy())
                .setExtData(data.getExtData());
        save(m);

        // 保存用户消息记录
        List<RoomUser> ruList = roomUserService.list(
                new LambdaQueryWrapper<RoomUser>().eq(RoomUser::getRoomId, data.getRoomId()));
        List<MsgStatus> msList = ruList.stream().map(ru -> new MsgStatus()
                .setRoomId(data.getRoomId())
                .setMsgId(m.getId())
                .setUserId(ru.getUserId())
                .setStatus(Integer.parseInt(ReadStatus.UN_READ.toCode())))
                .collect(Collectors.toList());
        msgStatusService.saveBatch(msList);

        // 更新房间最后一条
        Room r = new Room()
                .setId(data.getRoomId())
                .setLastMsg(data.getSimpleText())
                .setLastMsgSentBy(data.getSentBy())
                .setLastMsgAt(LocalDateTimeUtil.parse(data.getSentAt())) // yyyy-MM-ddTHH:mm:ss
                .setLastMsgSentByName(data.getSentByName());
        roomService.updateById(r);

        // 推送消息
        sessionService.sendMessageByRoomId(data.getRoomId()+"", AppConstant.SOCKET_EVENT_MESSAGE, data);
    }

    @Override
    public long getUnreadCount() {
        Integer loginUserId = Integer.parseInt(LoginUtil.getLoginUserIdOrException());
        return msgStatusService.countUnreadMsg(null, loginUserId);
    }

    private void sendUnreadCount(String userId) {
        long unreadCount = msgStatusService.countUnreadMsg(null, Integer.parseInt(userId));
        Map<String, Object> payload = new HashMap<>();
        payload.put("count", unreadCount);
        sessionService.sendMessageByUserId(userId, AppConstant.SOCKET_EVENT_UNREAD_COUNT, payload);
    }
}
